package cn.changeforyou.analyzer.combine.orm.compare.compareResultProcessor;

import cn.changeforyou.analyzer.combine.orm.compare.EntityAndTableComparetor.EntityAndTableCompareResult;
import cn.changeforyou.analyzer.combine.orm.compare.compareResultProcessor.cmdParamters.DeleteParameters;
import cn.changeforyou.analyzer.combine.orm.compare.compareResultProcessor.cmdParamters.InsertAndDeleteParameters;
import cn.changeforyou.analyzer.combine.orm.compare.compareResultProcessor.cmdParamters.InsertParameters;
import cn.changeforyou.analyzer.dbParse.model.MysqlTableInfo.ColumnInfo;
import cn.changeforyou.analyzer.javaparse.model.EntityModel.FieldInfo;
import cn.changeforyou.analyzer.javaparse.visitors.PairsAnnotationVisitor;
import cn.changeforyou.analyzer.javaparse.visitors.ReturnTypeParam;
import cn.changeforyou.cmd.generator.CmdGenerator;
import cn.changeforyou.cmd.generator.CmdGeneratorParameter;
import cn.changeforyou.cmd.generator.ConstantVar;
import cn.changeforyou.cmd.generator.GeneratorContext;
import cn.changeforyou.utils.string.StringUtils;
import com.baomidou.mybatisplus.generator.config.ConstVal;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.expr.NormalAnnotationExpr;
import com.google.common.io.Files;
import io.swagger.annotations.ApiModelProperty;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.collections.CollectionUtils;

/**
 * @author zhyu
 * @date 2021/2/19 11:06
 */
public class InsertAndDeleteFieldEntityCompareResultProcessor implements CmdGenerator {

    List<TableField> insert_tableInfo = new ArrayList<>();
    List<FieldInfo> delete_tableInfo = new ArrayList<>();
    EntityAndTableCompareResult result;
    Class<? extends CmdGeneratorParameter> cmdGeneratorParameter;
    boolean auto;

    @Override
    public String getSign() {
        return "insertAndDeleteFieldEntityCompareResultProcessor";
    }

    @Override
    public boolean generate_do(GeneratorContext context, CmdGeneratorParameter params) {
        ClassOrInterfaceDeclaration classOrInterfaceDeclaration = result.getEntityModel().getClassOrInterfaceDeclaration();
        File file = result.getEntityModel().getFile();

        if (params instanceof InsertParameters) {
            InsertParameters insertParameters = (InsertParameters) params;
            auto = insertParameters.isAll();
            if(auto) {
                insertField(classOrInterfaceDeclaration, null);
            }else {
                String insertNames = (insertParameters).getInsertNames();
                String[] names = getStrings(insertNames);
                insertField(classOrInterfaceDeclaration, names);
            }
        } else if (params instanceof DeleteParameters) {
            DeleteParameters deleteParameters = (DeleteParameters) params;
            auto = deleteParameters.isAll();
            if (auto) {
                deleteField(classOrInterfaceDeclaration, null);
            }else {
                String deleteFieldNames = (deleteParameters).getDeleteFieldNames();
                String[] names = getStrings(deleteFieldNames);
                deleteField(classOrInterfaceDeclaration, names);
            }
        }else {
            InsertAndDeleteParameters insertAndDelete = (InsertAndDeleteParameters) params;
            auto = insertAndDelete.isAll();
            if (auto) {
                insertAndDelete(classOrInterfaceDeclaration, null, null);
            }else {
                String insertNames = insertAndDelete.getInsertNames();
                String deleteFieldNames = insertAndDelete.getDeleteFieldNames();
                insertAndDelete(classOrInterfaceDeclaration, getStrings(insertNames), getStrings(deleteFieldNames));
            }
        }

        String newCode = classOrInterfaceDeclaration.getParentNode().get().toString();
        try {
            Files.write(newCode.getBytes(ConstVal.UTF8), file);
            log.info("java文件修改完毕");
        } catch (IOException e) {
            e.printStackTrace();
        }

        return true;
    }

    private void insertAndDelete(ClassOrInterfaceDeclaration classOrInterfaceDeclaration, String[] insertNames, String[] deleteNames) {
        insertField(classOrInterfaceDeclaration, insertNames);
        deleteField(classOrInterfaceDeclaration, deleteNames);
    }


    private void deleteField(ClassOrInterfaceDeclaration classOrInterfaceDeclaration, String[] names) {
        for (FieldInfo fieldInfo : delete_tableInfo) {
            String name = fieldInfo.getName();
            if (!auto && !StringUtils.in(name, names)) {
                continue;
            }

            FieldDeclaration fieldDeclaration = classOrInterfaceDeclaration.getFieldByName(name).get();
            classOrInterfaceDeclaration.remove(fieldDeclaration);
        }
    }

    private void insertField(ClassOrInterfaceDeclaration classOrInterfaceDeclaration, String[] names) {
        for (TableField tableField : insert_tableInfo) {
            String name = tableField.getPropertyName();
            if (!auto && !StringUtils.in(tableField.getName(), names)) {
                continue;
            }
            
            String type = tableField.getColumnType().getType();
            FieldDeclaration fieldDeclaration = classOrInterfaceDeclaration.addPrivateField(type, name);

            NormalAnnotationExpr normalAnnotationExpr = fieldDeclaration.addAndGetAnnotation(ApiModelProperty.class);
            PairsAnnotationVisitor<String> visitor = new PairsAnnotationVisitor<>();
            normalAnnotationExpr.accept(visitor, new ReturnTypeParam("value", tableField.getComment()));
        }
    }

    private String[] getStrings(String insertNames) {
        String[] split = insertNames.split(",");
        for (int i = 0; i < split.length; i++) {
            split[i] = split[i].trim();
        }
        return split;
    }

    @Override
    public String getName() {
        return "仅修改实体类处理器";
    }

    @Override
    public Class getParameterClass() {
        return cmdGeneratorParameter;
    }

    @Override
    public void init(GeneratorContext context) {
        result = context.getFromClassMap(EntityAndTableCompareResult.class);
        List<ColumnInfo> dbs = result.getDbs();
        List<FieldInfo> entitys = result.getEntitys();
        int operateCount = 0;

        if (CollectionUtils.isNotEmpty(dbs)) {
            operateCount++;
            StringBuilder str = new StringBuilder("数据库多出的字段为: \n");
            for (ColumnInfo db : dbs) {
                str.append("(").append(db.getColumnName()).append(" ").append(db.getColumnType()).append(" ").append(db.getColumnComment()).append(")\n");
            }
            str.deleteCharAt(str.length() - 1);
            log.info(str.toString());

            List<TableInfo> tableInfos = context.getFromKeyMap(ConstantVar.TABLE_INFO, List.class);
            String tableName = result.getMysqlTableInfo().getTableName();

            for (TableInfo tableInfo : tableInfos) {
                if (tableInfo.getName().equals(tableName)) {
                    List<TableField> fields = tableInfo.getFields();
                    for (TableField field : fields) {
                        for (ColumnInfo columnInfo : dbs) {
                            if (field.getName().equals(columnInfo.getColumnName())) {
                                insert_tableInfo.add(field);
                                break;
                            }
                        }
                    }
                }
            }
        }

        if (CollectionUtils.isNotEmpty(entitys)) {
            operateCount += 2;
            StringBuilder str = new StringBuilder("实体类多出的字段为: \n");
            for (FieldInfo info : entitys) {
                str.append("(").append(info.getName()).append(" ").append(info.getJavaType()).append(" ").append(info.getComment()).append(")\n");
                delete_tableInfo.add(info);
            }
            str.deleteCharAt(str.length() - 1);
            log.info(str.toString());
        }
        switch (operateCount) {
            case 1:
                cmdGeneratorParameter = InsertParameters.class;
                break;
            case 2:
                cmdGeneratorParameter = DeleteParameters.class;
                break;
            default:
                cmdGeneratorParameter = InsertAndDeleteParameters.class;
        }
        log.info("请使用命令操作要删除或者添加的字段");
    }
}
